/*
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package au.com.domlogic.pvc.core.attr;

import au.com.domlogic.pvc.core.element.PVCElement;
import au.com.domlogic.pvc.core.element.PVCElementDecorator;
import java.io.Serializable;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * This mold allows the developer to shape an {@link Attr} outside of the
 * Document Context.
 *
 * Once the mold is instantiated and configured, developers can decorate an
 * {@link PVCElement} by constructing an {@link ElementDecorator} from it, passing
 * the subject {@link PVCElement} to the constructor.
 *
 * @author Domenic Figliomeni
 */
public class AttrMold implements Serializable {

    /**
     * The namespace to which the {@link Attr} belongs.
     */
    private String namespace;
    /**
     * The name of the {@link Attr}.
     */
    private String name;
    /**
     * The value of the {@link Attr}.
     */
    private String value;
    /**
     * A boolean, which is true, when this {@link AttrMold} is intended to be used as
     * an {@link Element} identifier in the {@link Document} context.
     */
    private boolean idAttr;

    /**
     * Default Constructor.
     */
    public AttrMold() {
    }

    /**
     * Alternative Constructor, which sets the name field.
     * @param name
     */
    public AttrMold(String name) {
        this();
        this.name = name;
    }

    /**
     * Alternative Constructor, which sets the name and value fields.
     * @param name
     * @param value
     */
    public AttrMold(String name, String value) {
        this(name);
        this.value = value;
    }

    /**
     * @return the namespace
     */
    public String getNamespace() {
        return namespace;
    }

    /**
     * @param namespace the namespace to set
     */
    public void setNamespace(String namespace) {
        this.namespace = namespace;
    }

    /**
     *
     * @return true if the namespace field is set
     */
    public boolean hasNamespace() {
        return !doesNotHaveName();
    }

    /**
     *
     * @return true if the namespace field is not set
     */
    public boolean doesNotHaveNamespace() {
        return (namespace == null || namespace.equals(""));
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     *
     * @param name the name to set
     */
    protected void setName(String name) {
        this.name = name;
    }

    /**
     *
     * @return true if the name field is set
     */
    public boolean hasName() {
        return !doesNotHaveName();
    }

    /**
     *
     * @return true if the name field is not set
     */
    public boolean doesNotHaveName() {
        return (name == null || name.equals(""));
    }

    /**
     * @return the value
     */
    public String getValue() {
        return value;
    }

    /**
     * @param value the value to set
     */
    public void setValue(String value) {
        this.value = value;
    }

    /**
     *
     * @return true if the value field is set
     */
    public boolean hasValue() {
        return !doesNotHaveValue();
    }

    /**
     *
     * @return true if the value field is not set
     */
    public boolean doesNotHaveValue() {
        return (value == null || value.equals(""));
    }

    public boolean isIdAttr() {
        return idAttr;
    }

    public void setIdAttr(boolean idAttr) {
        this.idAttr = idAttr;
    }

    /**
     * This {@link PVCElementDecorator} sets and attribute from this {@link AttrMold}
     * on the {@link PVCElement}, which it is decorating.
     */
    public class ElementDecorator extends PVCElementDecorator {

        /**
         * Constructor which Decorates the passed {@link PVCElement}.
         * @param element
         */
        public ElementDecorator(PVCElement element) {
            super(element);
        }

        @Override
        protected void decorate() {
            Attr attr;
            if (hasName() && hasValue()) {
                if (hasNamespace()) {
                    attr = this.getAttributeNodeNS(namespace, name);
                    if (attr != null && !isIdAttr()) {
                        attr.setValue(attr.getValue() + " " + value);
                    } else {
                        this.setAttributeNS(namespace, name, value);
                    }
                } else {
                    attr = this.getAttributeNode(name);
                    if (attr != null && !isIdAttr()) {
                        attr.setValue(attr.getValue() + "" + value);
                    } else {
                        this.setAttribute(name, value);
                    }
                }
                if (isIdAttr()) {
                    this.getUnderlyingElement().setIdAttribute(name, true);
                }
            }
        }
    }
}
